package com.inspur.cloud.service.dataspace;

import com.inspur.cloud.dao.dataspace.*;
import com.inspur.cloud.entity.dataspace.*;
import com.inspur.cloud.entity.dataspace.ao.resource.DistributeAO;
import com.inspur.cloud.entity.dataspace.dto.ResourceCommonDTO;
import com.inspur.cloud.entity.dataspace.dto.UserResourceRelationDTO;
import com.inspur.cloud.enums.PermissionEnum;
import com.inspur.cloud.enums.ResourceTypeEnum;
import com.inspur.cloud.enums.RoleEnum;
import com.inspur.cloud.exception.ApiException;
import com.inspur.cloud.security.AuthorizationHelper;
import com.inspur.cloud.util.StringUtil;
import com.inspur.cloud.util.TConstants;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class UserResourceRelationService {
    @Autowired
    private UserResRelationSerivce userResRelationSerivce;
    @Autowired
    private UserService userService;
    @Autowired
    RangerService rangerService;
    @Autowired
    private HdfsResourceService hdfsResourceService;
    @Autowired
    private HiveResourceService hiveResourceService;
    @Autowired
    private HbaseResourceService hbaseResourceService;
    @Autowired
    private YarnResourceService yarnResourceService;
    @Autowired
    private KafkaResourceService kafkaResourceService;
    @Autowired
    AuthService authService;

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 某个资源下的已分配租户和用户
     *
     * @param resourceId   资源ID
     * @param resourceType 资源类型
     * @param uid          资源属主
     * @return
     */
    public UserResourceRelationDTO queryUserByResourceIdExceptOwner(Integer resourceId, ResourceTypeEnum resourceType, Integer uid) {
        List<UserResourceRelationEntity> urs = userResRelationSerivce.findByResourceIdAndResourceType(resourceId, resourceType.name());
        UserEntity currentUser = AuthorizationHelper.getUser();
        List<String> tenantList = new ArrayList<>();
        List<String> userList = new ArrayList<>();
        UserResourceRelationDTO ur = new UserResourceRelationDTO();
        if (urs != null && urs.size() > 0) {
            List<Integer> users = new ArrayList();
            urs.stream().distinct().forEach(e -> users.add(e.getUserId()));
            List<UserEntity> userEntityList = userService.findByIdIn(users);
            for (UserEntity entity : userEntityList) {
                if (entity.getId().equals(currentUser.getId())) {
                    continue;
                }
                if (RoleEnum.Tenant.getValue().equals(entity.getRole())) {
                    tenantList.add(entity.getName());
                    continue;
                }
                if (RoleEnum.User.getValue().equals(entity.getRole()) && (currentUser.getId().equals(entity.getParentId()) || AuthorizationHelper.isAdmin(currentUser))) {
                    userList.add(entity.getName());
                }
            }
            ur.setTannetList(tenantList);//租户列表
            ur.setUserList(userList);//用户列表
        }
        return ur;
    }

    /**
     * 返回有权限分配和分享的用户数据
     *
     * @param distributeAO
     * @param share   是否是分享，管理员是没有分享功能的
     * @return
     */
    public List<UserEntity> getRealUser(DistributeAO distributeAO, Boolean share) {
        List<UserEntity> userList = new ArrayList<>();
        UserEntity currentUser=AuthorizationHelper.getUser();
        if (distributeAO.getUserIdList() != null && distributeAO.getUserIdList().size() > 0) {
            List<UserEntity> entityList=userService.findByIdIn(distributeAO.getUserIdList());
            if(entityList!=null && entityList.size()>0 && distributeAO.getUserIdList().size()>entityList.size()){
                //非空且小于传入的值,0需要排除，因为0表示删除
                throw new ApiException("包含了不存在的用户，请检查！");
            }
            userList.addAll(entityList);
        }
        if (distributeAO.getTenantIdList() != null && distributeAO.getTenantIdList().size() > 0) {
            List<UserEntity> entityTenList=userService.findByIdIn(distributeAO.getTenantIdList());
            if(entityTenList!=null && entityTenList.size()>0 && distributeAO.getTenantIdList().size()>entityTenList.size()){
                //非空且小于传入的值,0需要排除，因为0表示删除
                throw new ApiException("包含了不存在的租户，请检查！");
            }
            userList.addAll(entityTenList);
        }
        if (distributeAO.getUserList() != null && distributeAO.getUserList().size() > 0) {
            List<UserEntity> entityList=userService.findByNameIn(distributeAO.getUserList());
            if(entityList!=null && entityList.size()>0 && distributeAO.getUserList().size()>entityList.size()){
                //非空且小于传入的值,0需要排除，因为0表示删除
                throw new ApiException("包含了不存在的用户，请检查！");
            }
            userList.addAll(entityList);
        }
        if (distributeAO.getTenantList() != null && distributeAO.getTenantList().size() > 0) {
            List<UserEntity> entityTenList=userService.findByNameIn(distributeAO.getTenantList());
            if(entityTenList!=null && entityTenList.size()>0 && distributeAO.getTenantList().size()>entityTenList.size()){
                //非空且小于传入的值,0需要排除，因为0表示删除
                throw new ApiException("包含了不存在的租户，请检查！");
            }
            userList.addAll(entityTenList);
        }
        List<UserEntity> realUserList = new ArrayList<>();
        for (UserEntity userEntity : userList) {
            if (AuthorizationHelper.isAdmin()) {//管理员只能分给租户
                if (RoleEnum.Tenant.getValue().equals(userEntity.getRole())) {
                    realUserList.add(userEntity);
                }
            } else if (AuthorizationHelper.isTenant()) {//租户只能分配给自己的用户（如果是分享则没有这个限制）
                if (!share) {
                    if (RoleEnum.User.getValue().equals(userEntity.getRole()) && userEntity.getParentId().equals(currentUser.getId())) {
                        realUserList.add(userEntity);
                    }
                } else {
                    if (RoleEnum.Tenant.getValue().equals(userEntity.getRole())) {//租户只能分享给其他租户
                        realUserList.add(userEntity);
                    }
                }
            } else {//用户只有分享给同级用户这个功能
                if (share) {
                    if (RoleEnum.User.getValue().equals(userEntity.getRole()) && userEntity.getParentId().equals(currentUser.getParentId())) {
                        realUserList.add(userEntity);
                    }
                }
            }
        }
        return realUserList;
    }

    /**
     * 分配
     * 需要注意：管理员只能把一级公共资源分给租户，不能分私有资源。
     *
     * @param distributeAO
     * @param resourceTypeEnum
     * @param share 是否是共享
     * @return
     */
    public Integer distribute(DistributeAO distributeAO, ResourceTypeEnum resourceTypeEnum, Boolean share) {
        UserEntity currentUser = AuthorizationHelper.getUser();
        String auth = authService.getSourceAuth(distributeAO.getResourceId(), currentUser.getId(), resourceTypeEnum.getResourceType());
        if (!AuthorizationHelper.isAdmin() && StringUtils.isEmpty(auth)) {
            if (!share) {
                throw new ApiException("无权分配资源");
            } else {
                throw new ApiException("无权分享资源");
            }
        }
        if(AuthorizationHelper.isAdmin() && StringUtils.isEmpty(auth)){//如果是管理员，没有权限的话，给它最大权限
            auth= PermissionEnum.getAllPermissionByType(resourceTypeEnum.getType());
        }
        List<UserEntity> realUserList = getRealUser(distributeAO, share);//该用户能给哪些用户权限，主要是过滤掉postman乱提交的数据
        List<Integer> realIdList = new ArrayList<>();
        if (realUserList != null && realUserList.size() > 0) {
            realIdList.addAll(realUserList.stream().map(u -> u.getId()).collect(Collectors.toList()));
        }
        List<UserEntity> sonList = new ArrayList<>();
        if (!share) {//是分配
            sonList = userService.findByParentId(currentUser.getId());//找到该用户子用户
        } else {
            if (AuthorizationHelper.isAdmin()) {
                throw new ApiException("管理员只可分配，不可分享资源");
            } else if (AuthorizationHelper.isTenant(currentUser)) {
                sonList = userService.findByParentId(TConstants.ADMIN_ID);//租户可以分享给所有同级租户
            } else {
                sonList = userService.findByParentId(currentUser.getParentId());//用户可以分享给同级用户
            }
        }
        if (sonList == null || sonList.size() == 0) {
            throw new ApiException("没有可分配或共享的用户");
        }
        List<Integer> userIdList = new ArrayList<>();
        userIdList.addAll(sonList.stream().map(u -> u.getId()).collect(Collectors.toList()));
        List<UserEntity> addOrModifyUsers = realUserList;//传过来的合法用户就是需要增加权限的
        List<UserEntity> deleteUsers = new ArrayList<>();//要去掉权限的用户

        List<Integer> toDelIdList=new ArrayList<>();
        List<UserResourceRelationEntity> urList=userResRelationSerivce.findByResourceIdAndResourceType(distributeAO.getResourceId(),resourceTypeEnum.name());
        //找出该资源所分的所有用户
        for (UserResourceRelationEntity ur : urList) {
            //是儿子并且没在分配列表里，那就是删除
            if(userIdList.contains(ur.getUserId()) && !realIdList.contains(ur.getUserId())){
                toDelIdList.add(ur.getUserId());
            }
        }
        if(toDelIdList.size()>0){
            deleteUsers=userService.findByIdIn(toDelIdList);
        }

        //处理新增或修改权限(增加不用处理子用户)
        if (addOrModifyUsers != null && addOrModifyUsers.size() > 0) {
            //看看用户有没有权限，有就啥都不做，没有就加权限
            for (UserEntity addOrModifyUser : addOrModifyUsers) {
                UserResourceRelationEntity ur = userResRelationSerivce.findFirstByResourceIdAndUserIdAndResourceType(distributeAO.getResourceId(), addOrModifyUser.getId(), resourceTypeEnum.name());
                if (ur != null) {
                    continue;//用户有这个资源的权限了，那就啥都不做
                }
                //如果没有，那要看看有没有上一级资源权限，如果没有，那才加，有的话就不需要加。有了表权限，就不让加列权限
                String userAuth = authService.getSourceAuth(distributeAO.getResourceId(), addOrModifyUser.getId(), resourceTypeEnum.getResourceType());
                if (!StringUtils.isEmpty(userAuth)) {//上级资源有权限
                    continue;//不需要处理
                }
                //本级和上级都没有，开始找下级,如果下级已经有权限了，需要取消下级的，改为本级的(如果先加的列权限，现在要加表权限，那就取消列的，改为上级的)
                List<Integer> sonResourceId = getAllResourceSonId(distributeAO.getResourceId(), resourceTypeEnum.getResourceType());
                if (sonResourceId.size() > 0) {//把下级的干掉
                    //处理这种情况
                    for (Integer sonId : sonResourceId) {
                        deleteUserRelation(sonId, addOrModifyUser, resourceTypeEnum.getResourceType());
                    }
                }
                //还有一种情况，租户有列权限，需要加表权限，干掉列改为表,下面的用户呢？不需要考虑
                //本级和上级资源没有权限，下级也没有（有也被干掉了），那就开始给本级加权限
                ResourceCommonDTO resourceCommon = getResourceCommon(distributeAO.getResourceId(), resourceTypeEnum.getResourceType());
                rangerService.setPermissionInRanger(resourceTypeEnum.getResourceType(), resourceCommon.getContent(), auth, addOrModifyUser.getName());
                addUserRelation(resourceCommon, addOrModifyUser, resourceTypeEnum.getResourceType(), auth);
            }//end for addOrModifyUsers

        }//end do with addOrModifyUsers
        //处理减权限，需要考虑子用户
        if (deleteUsers != null && deleteUsers.size() > 0) {
            //找到在这个资源下的全部权限（包含子资源的，删除）。其实如果有这个资源权限，出于级联的原因，是不会有子资源权限的
            List<Integer> sonResourceId = getAllResourceSonId(distributeAO.getResourceId(), resourceTypeEnum.getResourceType());
            sonResourceId.add(distributeAO.getResourceId());//加上当前资源
            for (UserEntity deleteUser : deleteUsers) {
                if (deleteUser.getRole().equals(RoleEnum.Tenant.getValue())) {//如果要删除的是租户，还要处理它的子用户()
                    List<UserEntity> tenantSon = userService.findByParentId(deleteUser.getId());//找到租户的子用户
                    tenantSon.add(deleteUser);//加上租户自己
                    for (UserEntity userEntity : tenantSon) {
                        for (Integer sonId : sonResourceId) {//对于本资源和每个子资源都去处理权限
                            deleteUserRelation(sonId, userEntity, resourceTypeEnum.getResourceType());
                        }
                    }
                } else {//是用户，直接删就是了
                    for (Integer sonId : sonResourceId) {
                        deleteUserRelation(sonId, deleteUser, resourceTypeEnum.getResourceType());
                    }
                }
            }
        }//end for delUsers
        return sonList != null ? sonList.size() : 0;
    }


    public Integer addUserRelation(ResourceCommonDTO resourceCommon, UserEntity user, String type, String auth) {
        UserResourceRelationEntity ur = userResRelationSerivce.findFirstByResourceIdAndUserIdAndResourceType(resourceCommon.getId(), user.getId(), type);
        Date now = new Date();
        if (ur == null) {
            ur = new UserResourceRelationEntity();
            ur.setResourceContent(resourceCommon.getContent());
            ur.setAuthor(auth);
            ur.setResourceId(resourceCommon.getId());
            ur.setResourceLevel(resourceCommon.getLevel());
            ur.setResourceType(type);
            ur.setStatus(TConstants.RES_STATUS_AVAILABLE);
            ur.setUserId(user.getId());
            ur.setInsDate(new Date());
            ur.setUpdDate(now);
            userResRelationSerivce.save(ur);
            return ur.getId();
        }
        return ur.getId();
    }

    public Integer deleteUserRelation(Integer resourceId, UserEntity user, String type) {
        //数据库中存在多条数据，应属于脏数据,需全部删除
        List<UserResourceRelationEntity> urList = userResRelationSerivce.findAllResourceIdAndUserIdAndResourceType(resourceId, user.getId(), type);
        if (urList != null && urList.size()>0) {
            for (UserResourceRelationEntity ur : urList) {
                userResRelationSerivce.delete(ur);
            }
            ResourceCommonDTO resourceCommon = getResourceCommon(resourceId, type);
            rangerService.setPermissionInRanger(type, resourceCommon.getContent(), "", user.getName());
            return urList.size();
        }
        return 0;
    }

    /**
     * 调用此方法需要注意，先删权限后删资源
     * @param resourceId
     * @param type
     * @return
     */
    public Integer deleteAllUserRelations(Integer resourceId, String type) {
        List<UserResourceRelationEntity> urList = userResRelationSerivce.findByResourceIdAndResourceType(resourceId, type);
        List<Integer> userIdList=new ArrayList<>();
        if (urList != null && urList.size()>0) {
            for (UserResourceRelationEntity ur : urList) {
                if(!userIdList.contains(ur.getUserId())){
                    userIdList.add(ur.getUserId());
                }
                userResRelationSerivce.delete(ur);
            }
            //获取所有用户名
            List<String> usernameList = userService.findByIdIn(userIdList).stream().map(o -> o.getName()).collect(Collectors.toList());
            if(usernameList!=null && usernameList.size()>0) {
                ResourceCommonDTO resourceCommon = getResourceCommon(resourceId, type);
                String names="";
                try {
                    if(resourceCommon!=null) {
                        names = StringUtil.concat(usernameList, "|");
                        rangerService.setPermissionInRanger(type, resourceCommon.getContent(), "", names);
                    }
                }catch (Exception e){
                    logger.error("去掉资源权限出错: type={},content={},user={}",type,resourceCommon!=null?resourceCommon.getContent():"null",names);
                }
            }
            return urList.size();
        }
        return 0;
    }


    /**
     * 获取所有子资源ID，不包含自己，去重
     *
     * @param resourceId
     * @param type
     * @return
     */
    public List<Integer> getAllResourceSonId(Integer resourceId, String type) {
        List<Integer> resourceIdList = new ArrayList<>();
        resourceIdList.add(resourceId);
        int begin = 0;
        int end = 0;
        while (begin <= end) {
            List<Integer> ids = getResourceSonId(resourceIdList.get(begin), type);
            if (ids != null && ids.size() != 0) {
                resourceIdList.addAll(ids);
                end += ids.size();
            }
            begin++;
        }
        List<Integer> result = new ArrayList();
        for (Integer id : resourceIdList) {
            if (id.equals(resourceId)) {
                continue;//去掉自己
            }
            if (result.contains(id)) {
                continue;
            }
            result.add(id);
        }
        return result;
    }

    public List<Integer> getResourceSonId(Integer resourceId, String type) {
        ResourceCommonDTO result = new ResourceCommonDTO();
        switch (type) {
            case "HIVE":
                List<HiveResourceEntity> hiveList = hiveResourceService.findByParentId(resourceId);
                if (hiveList.size() > 0) {
                    return hiveList.stream().map(o -> o.getId()).collect(Collectors.toList());
                } else {
                    return null;
                }
            case "HDFS":
                List<HdfsResourceEntity> hdfsList = hdfsResourceService.findByParentId(resourceId);
                if (hdfsList.size() > 0) {
                    return hdfsList.stream().map(o -> o.getId()).collect(Collectors.toList());
                } else {
                    return null;
                }
            case "HBASE":
                List<HbaseResourceEntity> hbaseList = hbaseResourceService.findByParentId(resourceId);
                if (hbaseList.size() > 0) {
                    return hbaseList.stream().map(o -> o.getId()).collect(Collectors.toList());
                } else {
                    return null;
                }
            case "KAFKA":
                List<KafkaResourceEntity> kafkaList = kafkaResourceService.findByParentId(resourceId);
                if (kafkaList.size() > 0) {
                    return kafkaList.stream().map(o -> o.getId()).collect(Collectors.toList());
                } else {
                    return null;
                }
            case "YARN":
                List<YarnResourceEntity> yarnList = yarnResourceService.findByParentId(resourceId);
                if (yarnList.size() > 0) {
                    return yarnList.stream().map(o -> o.getId()).collect(Collectors.toList());
                } else {
                    return null;
                }

        }
        return null;
    }

    /**
     * 获取资源信息通用
     *
     * @param resourceId 资源id
     * @param type       资源类型
     * @return 资源信息
     */
    public ResourceCommonDTO getResourceCommon(Integer resourceId, String type) {
        ResourceCommonDTO result = new ResourceCommonDTO();
        switch (type) {
            case "HIVE":
                HiveResourceEntity hiveEntity = hiveResourceService.findHiveResourceEntityById(resourceId);
                if (hiveEntity == null) {
                    return null;
                } else {
                    String databaseName = hiveEntity.getDatabaseName();
                    String tableName = hiveEntity.getTableName();
                    String columnName = hiveEntity.getColumnName();
                    result.setContent(databaseName + "|" + (StringUtils.isEmpty(tableName) ? "*" : tableName) + "|" + (StringUtils.isEmpty(columnName) ? "*" : columnName));
                    result.setLevel(hiveEntity.getLevel());
                    result.setParentId(hiveEntity.getParentId());
                    result.setId(hiveEntity.getId());
                    result.setOwner(hiveEntity.getOwner());
                    return result;
                }
            case "HDFS":
                HdfsResourceEntity hdfsEntity = hdfsResourceService.findHdfsResourceEntityById(resourceId);
                if (hdfsEntity == null) {
                    return null;
                } else {
                    result.setId(hdfsEntity.getId());
                    result.setContent(hdfsEntity.getUrl());
                    result.setLevel(hdfsEntity.getLevel());
                    result.setParentId(hdfsEntity.getParentId());
                    result.setOwner(hdfsEntity.getOwner());
                    return result;
                }
            case "HBASE":
                HbaseResourceEntity hbaseEntity = hbaseResourceService.findHbaseResourceEntityById(resourceId);
                if (hbaseEntity == null) {
                    return null;
                } else {
                    String spaceName = hbaseEntity.getSpaceName();
                    String tableName = hbaseEntity.getTableName();
                    String columnFamilyName = hbaseEntity.getColumnFamilyName();
                    String columnName = hbaseEntity.getColumnName();
                    result.setContent(spaceName + ":" + (StringUtils.isEmpty(tableName) ? "*" : tableName) + "|" + (StringUtils.isEmpty(columnFamilyName) ? "*" : columnFamilyName) + "|" + (StringUtils.isEmpty(columnName) ? "*" : columnName));
                    result.setLevel(hbaseEntity.getLevel());
                    result.setParentId(hbaseEntity.getParentId());
                    result.setId(hbaseEntity.getId());
                    result.setOwner(hbaseEntity.getOwner());
                    return result;
                }
            case "YARN":
                YarnResourceEntity yarnEntity = yarnResourceService.findYarnResourceEntityById(resourceId);
                if (yarnEntity == null) {
                    return null;
                } else {
                    if (yarnEntity.getLevel() == 2) {
                        YarnResourceEntity yarnParentEntity = yarnResourceService.findYarnResourceEntityById(yarnEntity.getParentId());
                        result.setContent(String.format("root.%s.%s", yarnParentEntity.getQueueName(), yarnEntity.getQueueName()));
                    } else {
                        result.setContent(String.format("root.%s", yarnEntity.getQueueName()));
                    }
                    result.setLevel(yarnEntity.getLevel());
                    result.setParentId(yarnEntity.getParentId());
                    result.setId(yarnEntity.getId());
                    result.setOwner(yarnEntity.getOwner());
                    return result;
                }
            case "KAFKA":
                KafkaResourceEntity kafkaEntity = kafkaResourceService.findKafkaResourceEntityById(resourceId);
                if (kafkaEntity == null) {
                    return null;
                } else {
                    result.setContent(kafkaEntity.getTopicName());
                    result.setLevel(kafkaEntity.getLevel());
                    result.setParentId(kafkaEntity.getParentId());
                    result.setId(kafkaEntity.getId());
                    result.setOwner(kafkaEntity.getOwner());
                    return result;
                }
            default:
                break;
        }
        return null;
    }

}
